using System;
using System.Windows.Forms;

using OhioState.Graphics.Proxy;
using OhioState.Math;

namespace ShapeEditor
{
    public partial class BoxControl : UserControl
    {
        public BoxControl()
        {
            InitializeComponent();
        }
        //
        // Delegate for Plane Control
        //
        private delegate void BoxHandler(SharedBox SBOX);
        private SharedBox sBox;

        #region Public Properties
        public SharedBox SBOX
        {
            get { return sBox; }
        }

        //
        // Set the focus of this control to a new BOX.  Be careful of thread issues
        private void SetBox_thisThread(SharedBox SBOX)
        {
            sBox = null;
            //
            // Toggle Enabled based on whether the SBOX is null or not
            //
            if (SBOX == null)
            {
                this.Enabled = false;
            }
            else
            {
                this.Enabled = true;
                originXUpDown.Value = new Decimal(SBOX.LowerLeft.x);
                originYUpDown.Value = new Decimal(SBOX.LowerLeft.y);
                originZUpDown.Value = new Decimal(SBOX.LowerLeft.z);
                sizeXUpDown.Value = new Decimal(SBOX.Width);
                sizeYUpDown.Value = new Decimal(SBOX.Height);
                sizeZUpDown.Value = new Decimal(SBOX.Depth);
            }
            sBox = SBOX;
        }
        //
        // Force the event to get called on the proper thread.  The DataGridView complains if you try
        //  to use it on the wrong thread.
        //
        public void SetBox(SharedBox SBOX)
        {
            BoxHandler newEvent = new BoxHandler(SetBox_thisThread);
            object[] args = new object[1];
            args[0] = SBOX;
            //
            // We need to make sure these methods are executed on the correct thread.
            //
            try
            {
                if (this.InvokeRequired)
                    this.Invoke(newEvent, args);
                else
                    newEvent(SBOX);
            }
            catch { }
        }

        #endregion

        private void linkCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            linkedPicture.Visible = linkCheckBox.Checked;
        }

        private void originXUpDown_ValueChanged(object sender, EventArgs e)
        {
            if (sBox != null)
            {
                sBox.BeginManipulation();
                float x = sBox.LowerLeft.x;
                double x_new = Decimal.ToDouble(originXUpDown.Value);
                sBox.LowerLeft.x = (float)x_new;
                sBox.EndManipulation();
            }

        }

        private void originYUpDown_ValueChanged(object sender, EventArgs e)
        {
            if (sBox != null)
            {
                sBox.BeginManipulation();
                float y = sBox.LowerLeft.y;
                float y_new = Decimal.ToSingle(originYUpDown.Value);
                sBox.LowerLeft.y = y_new;
                sBox.EndManipulation();
            }
        }

        private void originZUpDown_ValueChanged(object sender, EventArgs e)
        {
            if (sBox != null)
            {
                sBox.BeginManipulation();
                float z = sBox.LowerLeft.z;
                float z_new = Decimal.ToSingle(originZUpDown.Value);
                sBox.LowerLeft.z = z_new;
                sBox.EndManipulation();
            }

        }

        private void sizeLinkedUpdate(float new_val, float old_val)
        {
            this.SuspendLayout();
            // Keep same ratio if possible
            if (sBox != null)
            {
                if (old_val != 0.0f)
                {
                    float ratio = new_val / old_val;
                    Vector3 ur = ratio * (sBox.UpperRight - sBox.LowerLeft) + sBox.LowerLeft;
                    sBox.UpperRight = ur;
                }
                //
                // TODO: we need to suspend changings around the call to this method, as this fires off
                //    a whole slew of changes.
                //
                sizeXUpDown.Value = new Decimal(sBox.Width);
                sizeYUpDown.Value = new Decimal(sBox.Height);
                sizeZUpDown.Value = new Decimal(sBox.Depth);
            }
        }
        private bool _changing = false;
        private void sizeXUpDown_ValueChanged(object sender, EventArgs e)
        {
            if (_changing)
                return;
            _changing = true;
            if (sBox != null)
            {
                sBox.BeginManipulation();
                float x = sBox.UpperRight.x - sBox.LowerLeft.x;
                float x_new = Decimal.ToSingle(sizeXUpDown.Value);
                if (linkCheckBox.Checked)
                {
                    sizeLinkedUpdate(x_new, x);
                }
                else
                {
                    sBox.Width = x_new;
                    sizeXUpDown.Value = new Decimal(sBox.Width);
                }
                sBox.EndManipulation();
            }
            _changing = false;

        }

        private void sizeYUpDown_ValueChanged(object sender, EventArgs e)
        {
            if (_changing)
                return;
            _changing = true;
            if (sBox != null)
            {
                sBox.BeginManipulation();
                float y = sBox.UpperRight.y - sBox.LowerLeft.y;
                float y_new = Decimal.ToSingle(sizeYUpDown.Value);
                if (linkCheckBox.Checked)
                {
                    sizeLinkedUpdate(y_new, y);
                }
                else
                {
                    sBox.Height = y_new;
                    sizeYUpDown.Value = new Decimal(sBox.Height);
                }
                sBox.EndManipulation();
            }
            _changing = false;
        }

        private void sizeZUpDown_ValueChanged(object sender, EventArgs e)
        {
            if (_changing)
                return;
            _changing = true;
            if (sBox != null)
            {
                sBox.BeginManipulation();
                float z = sBox.UpperRight.z - sBox.LowerLeft.z;
                float z_new = Decimal.ToSingle(sizeZUpDown.Value);
                if (linkCheckBox.Checked)
                {
                    sizeLinkedUpdate(z_new, z);
                }
                else
                {
                    sBox.Depth = z_new;
                    sizeZUpDown.Value = new Decimal(sBox.Depth);
                }
                sBox.EndManipulation();
            }
            _changing = false;
        }

        public void Visibility(bool isVisible)
        {
            if (this.InvokeRequired)
                this.Invoke((MethodInvoker)delegate { this.Visible = isVisible; });
            else
                this.Visible = isVisible;
        }               
    }
}